#include"../redis/campus_redis_connector.h"
#include "campus_redis_connector.h"
#include"../log/campus_logger.h"

CampusRedisConnector::CampusRedisConnector(std::string const& redis_url,int redis_port,int timeout_ms):
    redis_url_(redis_url),
    redis_port_(redis_port),
    redis_status_(CAMPUS_REDIS_DISCONNECTED)
{
    //设置超时时间
    timeout_.tv_sec = timeout_ms / 1000;
    timeout_.tv_usec = (timeout_ms % 1000) * 1000;
}

CampusRedisConnector::~CampusRedisConnector()
{
    disconnect();
}

int CampusRedisConnector::connect()
{
    if(is_connected_){
        CampusLogger::warn("CampusRedisConnector::connect,已连接，无需再次连接");
        return 1;
    }

    redis_context_ = std::unique_ptr<redisContext, RedisContextDeleter>(redisConnectWithTimeout(redis_url_.c_str(), redis_port_,timeout_));
    if (redis_context_ == nullptr || redis_context_->err)
    {
        if (redis_context_)
        {
            setError(redis_context_->errstr);
            redis_context_.reset();
            redis_context_ = nullptr;
        }
        else
        {
            setError("分配redis上下文失败");
        }
        return 1;
    }

    is_connected_ = true;
    redis_status_ = CAMPUS_REDIS_CONNECTED;

    CampusLogger::info("CampusRedisConnector Redis连接成功,url:{} port:{} timeout:{}ms",
        redis_url_,redis_port_,(timeout_.tv_sec * 1000 + timeout_.tv_usec /1000));

    return 0;
}

int CampusRedisConnector::disconnect()
{
    if(!is_connected_){
        CampusLogger::warn("CampusRedisConnector::disconnect,未连接，无需断开");
        return 1;
    }

    if(redis_context_){
        redis_context_.reset();
        redis_context_ = nullptr;

        is_connected_ = false;
        redis_status_ = CAMPUS_REDIS_DISCONNECTED;
    }
    CampusLogger::info("CampusRedisConnector::disconnect,断开成功");

    return 0;
}

CampusRedisStatus CampusRedisConnector::getStatus() const
{
    return redis_status_;
}

void CampusRedisConnector::setError(std::string const &error)
{
    
    CampusLogger::warn(" CampusRedisConnector::setError 错误信息:{}",error);
    last_error_ = error;
    redis_status_ = CAMPUS_REDIS_ERROR;
}


std::shared_ptr<redisReply> CampusRedisConnector::exec(const char* format, ...)
{
   if(redis_status_ != CAMPUS_REDIS_CONNECTED){
        setError("redis未连接");
        return nullptr;
   }

    std::lock_guard<std::mutex> lock(mutex_);

    va_list args;
    va_start(args, format);
    redisReply* reply = (redisReply*)redisvCommand(redis_context_.get(), format, args);
    va_end(args);

    if(reply == nullptr || reply->type == REDIS_REPLY_ERROR){
        setError("执行命令失败:" + std::string(format));
        return nullptr;
    }

    CampusLogger::info("CampusRedisConnector::exec,执行命令成功,命令:{}",format);

    return std::shared_ptr<redisReply>(reply,RedisReplyDeleter());
}

std::string CampusRedisConnector::get(std::string const& key)
{
    std::shared_ptr<redisReply> reply = exec("GET %s", key.c_str());
    if (reply == nullptr) {
        CampusLogger::warn("CampusRedisConnector::get,获取key失败,key:{}",key);
        return std::string();
    }

    if(reply->type != REDIS_REPLY_STRING){
        CampusLogger::warn("CampusRedisConnector::get,获取key失败,key:{}",key);
        return std::string();
    }

    CampusLogger::info("CampusRedisConnector::get,获取key成功,key:{} value:{}",key,reply->str);
    return std::string(reply->str,reply->len);
}

int CampusRedisConnector::set(std::string const& key,std::string const& value,int expire_seconds)
{
   std::shared_ptr<redisReply> reply = nullptr;
    
    if (expire_seconds > 0) {
        reply = exec("SET %s %s EX %d", key.c_str(), value.c_str(), expire_seconds);
    } else {
        reply = exec("SET %s %s", key.c_str(), value.c_str());
    }
    
    if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
        CampusLogger::warn("CampusRedisConnector::set,设置key失败,key:{}",key);
        return 1;
    }

    if(reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "OK") == 0){
        CampusLogger::info("CampusRedisConnector::set,设置key成功,key:{},reply_status:{}",key,reply->str);
    }
    
    return 0;
}

int CampusRedisConnector::init()
{
    return connect();
}

int CampusRedisConnector::exists(std::string const& key)
{
    std::shared_ptr<redisReply> reply = exec("EXISTS %s", key.c_str());

    if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
        CampusLogger::warn("CampusRedisConnector::exists,获取key失败,key:{}",key);
        return 1;
    }
    if(reply->type == REDIS_REPLY_INTEGER){
        CampusLogger::info("CampusRedisConnector::exists,获取key成功,key:{} value:{}",key,reply->integer);
    }
    return 0;
}

int CampusRedisConnector::del(std::string const& key)
{
    std::shared_ptr<redisReply> reply = exec("DEL %s", key.c_str());

    if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
        CampusLogger::warn("CampusRedisConnector::del,删除key失败,key:{}",key);
        return 1;
    }
    if(reply->type == REDIS_REPLY_INTEGER){
        if(reply->integer == 1){
            CampusLogger::info("CampusRedisConnector::del,删除key成功,key:{} value:{}",key,reply->integer);
        }
        else{
            CampusLogger::warn("CampusRedisConnector::del,删除key失败,key:{} value:{}",key,reply->integer);
        }
    }
    
    return 0;
}

int CampusRedisConnector::expire(std::string const& key,int seconds){
    std::shared_ptr<redisReply> reply = std::shared_ptr<redisReply>(
        exec("EXPIRE %s %d", key.c_str(), seconds));

    if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) {
        CampusLogger::warn("CampusRedisConnector::expire,设置key过期时间失败,key:{}",key);
        return 1;
    }
    if(reply->type == REDIS_REPLY_INTEGER){
        CampusLogger::info("CampusRedisConnector::expire,设置key过期时间成功,key:{} value:{}",key,reply->integer);
    }

    return 0;
}
